package outbound_account

import (
	"context"
	"encoding/json"
	"fmt"
	"git.mycaigou.com/gfyx/common/tenant_db"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/errcode"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/market/outbound_account"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/market/outbound_task"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/baiying_remote"
	pb "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/market"
	"git.myscrm.cn/golang/common/ykerrcode"
	"git.myscrm.cn/golang/stark/v4"
	"math"
	"time"
)

type OutboundAccountService struct {
	baiyingRepo baiying_remote.BaiYingRepositoryIface
	accountRepo outbound_account.OutboundAccountRepositoryIface
	taskRepo    outbound_task.OutBoundTaskRepositoryIface
}

func NewOutboundAccountService(
	baiyingRepo baiying_remote.BaiYingRepositoryIface,
	accountRepo outbound_account.OutboundAccountRepositoryIface,
	taskRepo outbound_task.OutBoundTaskRepositoryIface,
) OutboundAccountServiceIface {
	return &OutboundAccountService{
		baiyingRepo: baiyingRepo,
		accountRepo: accountRepo,
		taskRepo:    taskRepo,
	}
}

func (o *OutboundAccountService) GetRobotList(ctx context.Context, request *pb.GetRobotListRequest) (*pb.GetRobotListResponse, error) {
	var err error
	params := baiying_remote.RobotListRequest{}
	params.CompanyId = request.GetCompanyId()
	params.RobotStatus = request.GetRobotStatus()
	remoteResp, err := o.baiyingRepo.GetRobotList(ctx, request.CompanyId, &params)
	if err != nil {
		stark.Logger.Errorf(ctx, "CreateTask：调用百应获取话术接口失败，错误信息：%+v", err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetRobotLisError, "调用获取话术接口失败")
	}
	if remoteResp.Code != 200 {
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetRobotLisError, remoteResp.ResultMsg)
	}

	resp := &pb.GetRobotListResponse{}
	for _, v := range remoteResp.Data {
		resp.List = append(resp.List, &pb.RobotInfo{
			RobotDefId:      v.RobotDefId,
			RobotName:       v.RobotName,
			RobotStatus:     v.RobotStatus,
			IndustryOneName: v.IndustryOneName,
			IndustryTwoName: v.IndustryTwoName,
			DeployTime:      v.DeployTime,
		})
	}
	return resp, nil
}

func (o *OutboundAccountService) GetPhoneList(ctx context.Context, request *pb.GetPhoneListRequest) (*pb.GetPhoneListResponse, error) {
	var err error
	params := baiying_remote.PhoneListRequest{}
	params.CompanyId = request.GetCompanyId()
	remoteResp, err := o.baiyingRepo.GetPhoneList(ctx, request.CompanyId, &params)
	if err != nil {
		stark.Logger.Errorf(ctx, "CreateTask：调用百应获取线路列表接口失败，错误信息：%+v", err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetPhoneListError, "调用获取线路列表接口失败")
	}
	if remoteResp.Code != 200 {
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetPhoneListError, remoteResp.ResultMsg)
	}

	resp := &pb.GetPhoneListResponse{}
	resp.List = make([]*pb.PhoneInfo, 0)
	for _, v := range remoteResp.Data {
		resp.List = append(resp.List, &pb.PhoneInfo{
			UserPhoneId: v.UserPhoneId,
			PhoneName:   v.PhoneName,
			PhoneNum:    v.Phone,
			PhoneType:   v.PhoneType,
		})
	}
	return resp, nil
}

func (o *OutboundAccountService) GetSeatInfoList(ctx context.Context, request *pb.GetSeatInfoListRequest) (*pb.GetSeatInfoListResponse, error) {
	var err error
	params := baiying_remote.SeatInfoListRequest{}
	params.CompanyId = request.GetCompanyId()
	remoteResp, err := o.baiyingRepo.GetSeatInfoList(ctx, request.CompanyId, &params)
	if err != nil {
		stark.Logger.Errorf(ctx, "CreateTask：调用百应获取坐席列表接口失败，错误信息：%+v", err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetSeatListError, "调用获取坐席列表接口失败")
	}
	if remoteResp.Code != 200 {
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetSeatListError, remoteResp.ResultMsg)
	}

	resp := &pb.GetSeatInfoListResponse{}
	resp.AllCallSeat = remoteResp.Data.CompanyAllCallSeat
	resp.UsingCallSeat = remoteResp.Data.CompanyUsingCallSeat
	resp.List = make([]*pb.SeatInfo, 0)

	for _, v := range remoteResp.Data.CallSeatList {
		resp.List = append(resp.List, &pb.SeatInfo{
			StartTime:        v.ValidityBegin,
			EndTime:          v.ValidityEnd,
			RemainingDays:    v.RemainingDays,
			ConcurrencyQuota: v.ConcurrencyQuota,
			ServicePeriodId:  v.ServicePeriodId,
		})
	}
	return resp, nil
}

func (o *OutboundAccountService) GetBalance(ctx context.Context, request *pb.ExpenseDetailRequest) (*pb.ExpenseDetailResponse, error) {
	var err error
	params := &baiying_remote.GetBalanceRequest{}
	params.CompanyId = request.GetCompanyId()
	remoteResp, err := o.baiyingRepo.GetBalance(ctx, request.CompanyId, params)
	if err != nil {
		stark.Logger.Errorf(ctx, "CreateTask：调用百应获取公司AI账户余额接口失败，错误信息：%+v", err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetExpenseDetailError, "调用百应获取公司AI账户余额接口失败")
	}
	if remoteResp.Code != 200 {
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetExpenseDetailError, remoteResp.ResultMsg)
	}

	resp := &pb.ExpenseDetailResponse{}
	// 向下取整
	floorResult := math.Floor(remoteResp.Data.Amount)
	// 转换为int64
	resp.MinutesAmount = int64(floorResult) * 60
	resp.BillingModel = "按量付费"
	resp.SeatsNum = remoteResp.Data.Num
	return resp, nil
}

func (o *OutboundAccountService) GetAccountDetail(ctx context.Context, request *pb.GetAccountDetailRequest) (*pb.GetAccountDetailResponse, error) {
	// 构建请求参数
	conditions := make(map[string]interface{}, 0)
	if request.GetId() != 0 {
		conditions["id"] = request.GetId()
	}
	account, err := o.accountRepo.GetAccount(ctx, conditions)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetAccount 获取参数失败，请求参数: %v, 错误信息：%v", request, err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetDetailError, "获取账号详情信息失败")
	}

	return &pb.GetAccountDetailResponse{
		Id:          account.ID,
		AccountName: account.AccountName,
		CompanyId:   account.CompanyID,
		Status:      account.Status,
	}, nil
}


func (o *OutboundAccountService) GetExpenseDetail(ctx context.Context, request *pb.ExpenseDetailRequest) (*pb.ExpenseDetailResponse, error) {
	// 构建请求参数
	//conditions := make(map[string]interface{}, 0)
	//if request.GetId() != 0 {
	//	conditions["id"] = request.GetId()
	//}
	expenseDetailList, err := o.accountRepo.GetExpenseDetail(ctx)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetExpenseDetail 获取参数失败，请求参数: %v, 错误信息：%v", request, err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetExpenseDetailError, "获取明细详情失败")
	}
	pbDetailList := make([]*pb.ExpenseDetail, 0)
	var unitPrice float32
	unitPrice = 0.6
	for _, v := range expenseDetailList {
		pbDetailList = append(pbDetailList, &pb.ExpenseDetail{
			Date:            v.Date[:10],
			DurationMinutes: v.DurationMinutes,
			UnitPrice:      unitPrice,
		})
	}
	resp := &pb.ExpenseDetailResponse{}
	resp.DetailList = pbDetailList

	params := &baiying_remote.GetBalanceRequest{}
	params.CompanyId = request.GetCompanyId()
	remoteResp, err := o.baiyingRepo.GetBalance(ctx, params.CompanyId, params)
	if err != nil {
		stark.Logger.Errorf(ctx, "CreateTask：调用百应获取公司AI账户余额接口失败，错误信息：%+v", err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetExpenseDetailError, "调用百应获取公司AI账户余额接口失败")
	}
	if remoteResp.Code != 200 {
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetExpenseDetailError, remoteResp.ResultMsg)
	}

	// 转换为int64
	resp.MinutesAmount = int64(remoteResp.Data.Amount * 10)
	resp.BillingModel = "按量付费"
	resp.SeatsNum = remoteResp.Data.Num
	resp.UnitPrice = unitPrice
	return resp, nil
}

// SaveAccount 保存账号信息
// 由于只有编辑页面没有列表，所以取值是默认取一条，没有 id
// 业务逻辑流程
func (o *OutboundAccountService) SaveAccount(ctx context.Context, request *pb.SaveAccountRequest) (*pb.SaveAccountResponse, error) {
	// 校验参数，获取任务数据，如果存在就插入，不存在就更新
	conditions := make(map[string]interface{}, 0)
	conditions["id"] = request.Id
	account, err := o.accountRepo.GetAccount(ctx, conditions)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetAccount 获取参数失败，请求参数: %v, 错误信息：%v", request, err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetDetailError, "获取账号详情信息失败")
	}
	// 2. 校验这个参数有没有在其他租户被绑定
	tenantCode, _ := tenant_db.GetTenantCode(ctx)
	if code, _ := utils.GetTenantCodeForBy(ctx, request.CompanyId); code != "" && code != tenantCode {
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountHasExistError, "当前的 company id 已经被使用")
	}

	// 3, 判断 companyId 是否合法，调用一个线路接口
	params := baiying_remote.SeatInfoListRequest{CompanyId: request.CompanyId}
	resp, err := o.baiyingRepo.GetSeatInfoList(ctx, request.CompanyId, &params)
	if err != nil || resp.Code == 40000010 {
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountUnValidCompanyIdError, "无效的 company id")
	}

	// 4. 判断原先 companyId 下，是否有未完成的任务
	companyId := account.CompanyID
	if companyId == 0 {
		companyId = request.CompanyId
	}
	_, list, err := o.taskRepo.GetTaskList(ctx, map[string]interface{}{
		"company_id": companyId,
	}, nil)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetTaskList 获取参数失败，参数: %v, 错误信息：%v", companyId, err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountGetDetailError, "获取账号详情信息失败")
	}
	taskIds := make([]int64, 0)
	for _, v := range list {
		taskIds = append(taskIds, v.RealTaskId)
	}
	// 如果有待跑的任务，则批量调用百应的接口
	if len(taskIds) > 0 {
		taskIdsStr, _ := json.Marshal(taskIds)
		paramsRequest := &baiying_remote.GetBatchJobStatusListRequest{
			CompanyId:     companyId,
			CallJobIdList: string(taskIdsStr),
		}

		remoteResp, err := o.baiyingRepo.GetBatchJobStatusList(ctx, companyId, paramsRequest)
		if err != nil {
			stark.Logger.Errorf(ctx, "GetBatchJobStatusList：调用百应批量获取状态接口失败，请求参数：%+v, 错误信息：%+v", paramsRequest, err)
			return nil, ykerrcode.TogRPCError(errcode.OutboundTaskBatchStatusError, "调用百应批量获取状态接口失败")
		}
		if remoteResp.Code != 200 {
			return nil, ykerrcode.TogRPCError(errcode.OutboundAccountUnValidCompanyIdError, remoteResp.ResultMsg)
		}
		for _, v := range remoteResp.Data {
			if v.Status == constants.TaskStatusInProgress || v.Status == constants.TaskStatusQueuing {
				return nil, ykerrcode.TogRPCError(errcode.OutboundAccountHasRunTaskError, fmt.Sprintf("存进行中的任务，任务id：%d", v.CallJobId))
			}
		}
	}

	// 保存数据到数据库
	var oldCompanyId int64
	oldCompanyId = account.CompanyID
	userIdStr := fmt.Sprintf("%d", request.UserId)
	if account.ID == 0 {
		account.CreatedBy = userIdStr
		account.CreatedOn = time.Now()
	}
	account.Status = 1
	account.AccountName = request.AccountName
	account.CompanyID = request.CompanyId
	account.ModifiedBy = userIdStr
	account.ModifiedOn = time.Now()
	account.IsDeleted = constants.IsDeletedFalse
	id, err := o.accountRepo.SaveAccount(ctx, account)
	if err != nil {
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountSaveDetailError, "保存账号失败")
	}
	// 设置缓存
	_, err = utils.SetByRelation(ctx, tenantCode, request.CompanyId, oldCompanyId)
	if err != nil {
		stark.Logger.Errorf(ctx, "utils.SetRelation err, key:%s, id:%d, err: %+v", tenantCode, request.CompanyId, err)
		return nil, ykerrcode.TogRPCError(errcode.OutboundAccountSaveDetailError, "保存账号失败")
	}

	return &pb.SaveAccountResponse{
		Id: id,
	}, nil
}
